/**
 * 默认页面中的基本增删改查操作（弹窗类页面）
 */

/****
 * 添加日期范围
 * @param {*} params 原始数据
 * @param {*} dateRange 获取数据的字段名，或者 时间 数组数据
 * @param {*} propName 传给后台的字段后缀
 * @returns 处理之后的数据
 */
export function addDateRange(params, dateRange, propName) {
	try {
		const search = clone(params);
		const str = typeof dateRange === 'string';
		const [startTime = '', endTime = ''] = str ? search[dateRange] || [] : dateRange || [];
		if (typeof propName === 'undefined') {
			search['startTime'] = startTime;
			search['endTime'] = endTime;
		} else {
			search['start' + propName] = startTime;
			search['end' + propName] = endTime;
		}
		if (str) delete search[dateRange];
		return search;
	} catch (error) {
		console.log(error);
	}
}

// 响应数据转换（对象/函数）
function typeFn(data) {
	return typeof data === 'function' ? data?.() : data;
}

/***
 * 弹窗，新增，修改，详情
 * @param {Object} api 页面的增、删、改、查接口 默认对应 add、remove、edit、page
 * @param {String} id 表格数据的唯一标识，用于数据删除使用
 * @param {Object} dialogDefault 页面新增、修改、详情弹窗默认数据
 * @param {reactive} state 分页表格数据，为了处理删除完本页面数据需要返回上一页
 * @param {shallowRef} refTable 分页组件dom
 * @param {Function} getList 操作完之后，重新执行数据查询
 * @param {Object} props 接收多余未解构数据，兼容默认传递相关参数功能
 * @returns
 */
export function dialogMixin({ api = {}, id = 'id', dialogDefault = {}, state, refTable, getList, ...props } = {}) {
	const refDialogForm = props.refDialogForm ?? shallowRef(null), //新增弹窗的form表单的dom数据，用户新增，修改等表单校验
		tableSelection = props.tableSelection ?? ref([]), // 表格选中数据
		// 页面新增、修改、详情弹窗数据
		dialog =
			props.dialog ??
			reactive({
				title: '窗口',
				open: false,
				name: 'insert',
				form: {
					id: undefined
				},
				...dialogDefault
			});

	// 弹窗Title计算逻辑
	const dialogTitle = computed(() => {
		if (dialog.name === 'insert') return `新增${dialog.title}`;
		if (dialog.name === 'update') return `修改${dialog.title}`;
		if (dialog.name === 'detail') return `${dialog.title}详情`;
	});
	// 新增信息
	function insertFn(callback) {
		resetForm(unref(refDialogForm));
		dialog.name = 'insert';
		dialog.open = true;
		dialog.form.id = undefined;
		callback?.(dialog.form);
	}
	// 删除信息
	function deleteFn(data, callback) {
		// 删除单条
		if (!Array.isArray(data)) {
			confirm('此操作将删除该条数据, 是否继续?')
				.then(() => {
					typeFn(api)
						?.remove({ ids: `${data[id]}` })
						?.then(() => {
							if (refTable && 1 === unref(state).list.length) {
								unref(refTable)?.prevFn?.();
							} else {
								getList?.();
							}
							callback?.();
							msgSuccess('删除成功');
						});
				})
				.catch(() => {
					msgInfo('已取消删除！');
				});
		} else {
			// 删除多条
			confirm('此操作将删除选中数据, 是否继续?')
				.then(() => {
					typeFn(api)
						?.remove({ ids: data.map((item) => item[id]).join(',') })
						?.then(() => {
							if (refTable && data.length === unref(state).list.length) {
								unref(refTable)?.prevFn?.();
							} else {
								getList?.();
							}
							callback?.();
							msgSuccess('删除成功');
						});
				})
				.catch(() => {
					msgInfo('已取消删除！');
				});
		}
	}
	// 修改、详情逻辑
	function dialogOpen(row, name, callback) {
		dialog.name = name;
		if (typeFn(api).info) {
			typeFn(api)
				?.info({ id: row[id] })
				?.then((res) => {
					dialog.open = true;
					nextTick(() => {
						dialog.form = res.data;
						callback?.(dialog.form);
					});
				});
		} else {
			dialog.open = true;
			nextTick(() => {
				dialog.form = clone(row);
				callback?.(dialog.form);
			});
		}
	}
	// 修改信息
	function updateFn(row, callback) {
		dialogOpen(row, 'update', callback);
	}
	// 详情信息
	function detailFn(row, callback) {
		dialogOpen(row, 'detail', callback);
	}
	// 弹窗提交函数
	function dialogSubmitFn(preFn, sufFn) {
		const DialogForm = unref(refDialogForm),
			Form = DialogForm?.$refs?.refMyForm || DialogForm,
			data = cloneDeep(dialog.form);
		// 删除无需传递的数据
		delete data.createBy;
		delete data.createId;
		delete data.createTime;
		delete data.updateBy;
		delete data.updateId;
		delete data.updateTime;
		// 前置逻辑
		preFn?.(data);
		Form.validate((valid) => {
			if (valid) {
				typeFn(api)
					?.[dialog.name === 'insert' ? 'add' : 'edit'](data)
					?.then(() => {
						msgSuccess('操作成功！');
						dialog.open = false;
						getList?.();
						// 后置逻辑
						sufFn?.(dialog.form);
					});
			}
		});
	}
	return {
		refDialogForm,
		tableSelection,
		dialog,
		dialogTitle,
		insertFn,
		deleteFn,
		updateFn,
		detailFn,
		dialogSubmitFn
	};
}

/**
 * 普通表格分页查询  例：src/views/system/config.vue
 * @param {Function} loadDataCallback 加载完数据之后的逻辑
 * @param {Array} queryFormItem 页面的查询my-form的form表单动态化数据，查询条件中有时间数组需要数据转换的  该参数则必传
 * @param {Object} queryParamsDefault 查询条件数据对象、默认值
 * @param {Array} columns 页面用于生成表格的columns数据
 * @param {Object} api 页面的增、删、改、查接口 默认对应 add、remove、edit、page、info
 * @param {String} id 表格数据的唯一标识，用于数据删除使用
 * @param {Object} dialogDefault 页面新增、修改、详情弹窗默认数据
 * @param {Object} props 接收多余未解构数据，兼容默认传递相关参数功能
 * @returns
 */
export function pageMixin({
	loadDataCallback,
	queryFormItem = [],
	queryParamsDefault = {},
	columns = [],
	api = {},
	id = 'id',
	dialogDefault = {},
	...props
} = {}) {
	const queryParams =
			props.queryParams ??
			ref({
				...queryParamsDefault //查询条件数据对象
			}),
		// 页面表格数据
		state =
			props.state ??
			reactive({
				total: 0,
				list: [],
				columns
			}),
		refTable = props.refTable ?? shallowRef(null), //表格分页组件的dom数据，用户操作查询和重置分页查询等功能
		// 弹窗相关数据、逻辑
		{ refDialogForm, tableSelection, dialog, dialogTitle, insertFn, deleteFn, updateFn, detailFn, dialogSubmitFn } = dialogMixin({
			api,
			id,
			dialogDefault,
			state,
			refTable,
			getList,
			...props
		});
	// 表格排序
	function sortChange({ prop, order }) {
		unref(queryParams)['orderAndSc'] = `${prop}_${order === 'ascending' ? 'asc' : 'desc'}`; // true为升序false为降序
		unref(refTable)?.reload?.();
	}

	// 表格头部筛选字段统计函数
	const filterKeys = computed(() => state.columns.reduce((acc, item) => (item.filter ? [...acc, item.filter.prop] : acc), []));
	// 重置表格头部筛选条件
	function filterKeysFn() {
		for (const item of filterKeys.value) {
			unref(queryParams)[item] = '';
		}
	}

	// 页面查询函数
	function getList() {
		unref(refTable)?.loadData?.();
	}
	// 初始化表格查询逻辑
	function loadData(pageNum, pageSize) {
		let data = clone(unref(queryParams));
		if (unref(queryFormItem)) {
			// 时间组件
			const dateList = unref(queryFormItem).filter((item) => item.itemType === 'date' && item?.type?.match(/range/gi));
			dateList.forEach((item) => {
				const { prop, prepend } = item;
				data = addDateRange(data, prop, prepend);
			});
		}
		return typeFn(api)
			?.page?.({ pageNum, pageSize, ...data })
			?.then((res) => {
				unref(state).total = res.data?.total;
				unref(state).list = res.data?.rows;
				loadDataCallback?.(unref(state).list);
			});
	}

	return {
		queryParams,
		state,
		refTable,
		refDialogForm,
		tableSelection,
		dialog,
		dialogTitle,
		getList,
		sortChange,
		filterKeysFn,
		loadData,
		insertFn,
		deleteFn,
		updateFn,
		detailFn,
		dialogSubmitFn
	};
}

/**
 * 普通列表不分页
 * @param {Boolean} isAuto 是否自动加载数据
 * @param {Function} loadDataCallback 加载完数据之后的逻辑
 * @param {Array} queryFormItem 页面的查询my-form的form表单动态化数据，查询条件中有时间数组需要数据转换的  该参数则必传
 * @param {Object} queryParamsDefault 查询条件数据对象、默认值
 * @param {Object} api 页面的增、删、改、查接口 默认对应 add、remove、edit、list
 * @param {String} id 表格数据的唯一标识，用于数据删除使用
 * @param {Object} dialogDefault 页面新增、修改、详情弹窗默认数据
 * @param {Object} props 接收多余未解构数据，兼容默认传递相关参数功能
 * @returns
 */
export function listMixin({
	isAuto = true,
	loadDataCallback,
	queryFormItem = [],
	queryParamsDefault = {},
	api = {},
	id = 'id',
	dialogDefault = {},
	...props
} = {}) {
	const queryParams =
			props.queryParams ??
			ref({
				...queryParamsDefault //查询条件数据对象
			}),
		// 列表数据
		list = ref(props.list ?? []),
		// 弹窗相关数据、逻辑
		{ refDialogForm, dialog, tableSelection, dialogTitle, insertFn, deleteFn, updateFn, detailFn, dialogSubmitFn } = dialogMixin({
			api,
			id,
			dialogDefault,
			getList: loadData,
			...props
		});

	// 查询逻辑
	function loadData() {
		let data = clone(unref(queryParams));
		if (unref(queryFormItem)) {
			// 时间组件
			const dateList = unref(queryFormItem).filter((item) => item.itemType === 'date' && item?.type?.match(/range/gi));
			dateList.forEach((item) => {
				const { prop, prepend } = item;
				data = addDateRange(data, prop, prepend);
			});
		}
		return typeFn(api)
			?.list?.(data)
			?.then((res) => {
				list.value = res.data;
				loadDataCallback?.(list.value);
			});
	}
	// 初始化执行
	if (isAuto) loadData();
	return {
		queryParams,
		list,
		tableSelection,
		refDialogForm,
		dialog,
		dialogTitle,
		loadData,
		insertFn,
		deleteFn,
		updateFn,
		detailFn,
		dialogSubmitFn
	};
}

/**
 * 树形表格不分页查询 例：src/views/system/menu.vue
 * @param {Boolean} isAuto 是否自动加载数据
 * @param {Function} loadDataCallback 加载完数据之后的逻辑
 * @param {Array} queryFormItem 页面的查询my-form的form表单动态化数据，查询条件中有时间数组需要数据转换的  该参数则必传
 * @param {Object} queryParamsDefault 查询条件数据对象、默认值
 * @param {Array} columns 页面用于生成表格的columns数据
 * @param {Object} api 页面的增、删、改、查接口 默认对应 add、remove、edit、list
 * @param {String} id 表格数据的唯一标识，用于数据删除使用
 * @param {Object} dialogDefault 页面新增、修改、详情弹窗默认数据
 * @param {Object} props 接收多余未解构数据，兼容默认传递相关参数功能
 * @returns
 */
import { find } from './tree';
export function treeMixin({
	isAuto = true,
	loadDataCallback,
	queryFormItem = [],
	queryParamsDefault = {},
	columns = [],
	api = {},
	id = 'id',
	dialogDefault = {},
	...props
} = {}) {
	const queryParams =
			props.queryParams ??
			ref({
				...queryParamsDefault //查询条件数据对象
			}),
		//页面表格数据
		state =
			props.state ??
			reactive({
				list: [],
				columns,
				loadFnResolve: new Set()
			}),
		refTable = props.refTable ?? shallowRef(null), //表格分页组件的dom数据，用户操作查询和重置分页查询等功能
		// 弹窗相关数据、逻辑
		{ tableSelection, refDialogForm, dialog, dialogTitle, insertFn, deleteFn, updateFn, detailFn, dialogSubmitFn } = dialogMixin({
			api,
			id,
			dialogDefault,
			getList: loadData,
			...props
		});

	// 查询逻辑
	let totalList = ref([]);
	function loadData() {
		let data = clone(unref(queryParams));
		if (unref(queryFormItem)) {
			// 时间组件
			const dateList = unref(queryFormItem).filter((item) => item.itemType === 'date' && item?.type?.match(/range/gi));
			dateList.forEach((item) => {
				const { prop, prepend } = item;
				data = addDateRange(data, prop, prepend);
			});
		}
		return typeFn(api)
			?.list?.(data)
			?.then((res) => {
				const data = res.data?.rows || res.data;
				totalList.value = cloneDeep(data);
				unref(state).list = data.map((item) => {
					item.hasChildren = item?.children?.length > 0;
					item.children && delete item.children;
					return item;
				});
				for (const key of unref(state).loadFnResolve.keys()) {
					refTable.value.$refs.myTable.store.states.lazyTreeNodeMap.value[key] = loadLazyData(key);
				}
				loadDataCallback?.();
			});
	}
	function loadLazyData(key, resolve) {
		const data = cloneDeep(find(totalList.value, true, (item) => item.id === key).children);
		data.forEach((item) => {
			item.hasChildren = item?.children?.length > 0;
			item.children && delete item.children;
			return item;
		});
		resolve && resolve(data);
		return data;
	}

	// 初始化执行
	if (isAuto) loadData();
	return {
		queryParams,
		state,
		totalList,
		loadLazyData,
		refTable,
		refDialogForm,
		tableSelection,
		dialog,
		dialogTitle,
		loadData,
		insertFn,
		deleteFn,
		updateFn,
		detailFn,
		dialogSubmitFn
	};
}

/**
 * 表格跨页选择事件逻辑封装 tableSelection，lists，必须使用响应式state传递，例子my-tree-table
 * @param {Array} queryFormItem 页面的查询my-form的form表单动态化数据，查询条件中有时间数组需要数据转换的  该参数则必传
 * @param {Object} queryParamsDefault 查询条件数据对象、默认值
 * @param {Array} columns 页面用于生成表格的columns数据
 * @param {Object} api 页面的增、删、改、查接口 默认对应 add、remove、edit、page
 * @param {String} id 表格数据的唯一标识，用于数据删除使用
 * @param {Object} props 接收多余未解构数据，兼容默认传递相关参数功能
 * @returns
 */
export function spreadPage({ queryFormItem = [], queryParamsDefault = {}, columns, api = {}, id = 'id', ...props } = {}) {
	const queryParams =
			props.queryParams ??
			ref({
				...queryParamsDefault // 查询条件数据对象
			}),
		// 页面表格数据
		state =
			props.state ??
			reactive({
				total: 0,
				list: [],
				columns
			}),
		myTable = props.myTable ?? shallowRef(null), // 表格分页组件的dom
		tableSelection = props.tableSelection ?? ref([]); // 表格选中数据

	// 初始化表格查询逻辑
	function loadData(pageNum, pageSize) {
		let data = clone(unref(queryParams));
		if (unref(queryFormItem)) {
			// 时间组件
			const dateList = unref(queryFormItem).filter((item) => item.itemType === 'date' && item?.type?.match(/range/gi));
			dateList.forEach((item) => {
				const { prop, prepend } = item;
				data = addDateRange(data, prop, prepend);
			});
		}
		return typeFn(api)
			?.page?.({ pageNum, pageSize, ...data })
			?.then((res) => {
				unref(state).total = res.data?.total;
				unref(state).list = res.data?.rows;
				// 跨页缓存选中数据的功能
				nextTick(() => {
					const Ids = unref(tableSelection).map((item) => item[id]);
					unref(state).list.forEach((row, i) => {
						if (Ids.includes(row[id])) unref(myTable)?.$refs?.myTable?.toggleRowSelection(state.list[i], true);
					});
				});
			});
	}
	/**
	 * @description: 删除tableSelection数组中某项数据
	 * @param row 行数据
	 */
	function handleDelItem(row) {
		const index = unref(tableSelection).findIndex((item) => item[id] === row[id]);
		if (index >= 0) {
			unref(tableSelection).splice(index, 1);
		}
	}
	/**
	 * @description:  单选
	 * @param row 行数据
	 */
	function handleSelectionChange(selection, row) {
		// isExited判断tableSelection是否已经存在当前项
		if (unref(tableSelection).some((item) => item[id] === row[id])) {
			// 若存在，代表操作是 取消选中
			handleDelItem(row);
		} else {
			// 反之，选中某项
			unref(tableSelection).push(row);
		}
	}
	/**
	 * @description: 全选
	 * @param selection 数据
	 */
	function handleSelectionAllChange(selection) {
		if (selection.length === 0) {
			// 若是全不选，则循环删除tableSelection数组中存在的项
			unref(state).list.forEach((item) => {
				handleDelItem(item);
			});
		} else {
			// 全选，将selected和当前table数据合起来 并去重
			const obj = {};
			// 去重
			tableSelection.value = [...unref(tableSelection), ...unref(state).list].reduce((prev, next) => {
				obj[next[id]] ? '' : (obj[next[id]] = true && prev.push(next));
				return prev;
			}, []);
		}
	}
	return {
		queryParams,
		state,
		myTable,
		tableSelection,
		loadData,
		handleSelectionChange,
		handleSelectionAllChange
	};
}
